package com.douing.ad.dsp.bidding.tj.utils;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.lang.reflect.InvocationTargetException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import org.springframework.util.CollectionUtils;

public class TongJiUtil {

    private static LinkedList<NodeObj> linkedList = new LinkedList<NodeObj>();

    private static SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:00");

    private static SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    private static SimpleDateFormat sdf3 = new SimpleDateFormat("yyyy-MM-dd");

    private static String filePath = "/data/www/java/work/logs/";

    // linkedList 限制大小
    private static int limit = 2;

    // 时间间隔
    private static int timespace = 5;

    // 最后修改时间戳
    private static long lastUpdateTime = 0L;

    // 执行定时任务
    final static ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();

    // 锁
    final static Lock lock = new ReentrantLock();

    static {

        Runnable runnable = new Runnable() {
            public void run() {
                lock.lock();
                try {
                    // 如果5分钟没有操作
                    if (((new Date().getTime() - lastUpdateTime) / 60 * 1000) > 1) {
                        if (linkedList != null) {
                            // 全部输出
                            for (NodeObj nodeObj : linkedList) {
                                DataResult dataResult = getNodeObj(nodeObj);
                                write(dataResult);
                            }
                            // 全部删除
                            linkedList.removeAll(linkedList);
                            linkedList.clear();
                            linkedList = null;
                        }
                    }
                } catch (Exception ex) {
                    // 防止出现异常，导致定时任务停止
                    ex.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
        };

        // 定时任务(5分钟)
        service.scheduleAtFixedRate(runnable, 0, 1 * 60, TimeUnit.SECONDS);

    }

    /**
     * 处理人口
     * 
     * @param nodeData
     */
    public static void handle(NodeData nodeData) {
        lock.lock();
        try {
            // 修改时间戳
            lastUpdateTime = new Date().getTime();

            put(nodeData);

            if (linkedList.size() > limit) {
                DataResult dataResult = getFirst();
                write(dataResult);
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public static void put(NodeData nodeData) {
        try {
            if (linkedList == null) {
                linkedList = new LinkedList<NodeObj>();
            }
            if (linkedList.isEmpty()) {
                Date requestDate = nodeData.getRequestDate();
                NodeObj nodeObj = new NodeObj();

                String dateStr = sdf1.format(requestDate);
                Date dateFrom = sdf2.parse(dateStr);
                Date dateTo = getNextMinutes(dateFrom,timespace);
                
                nodeObj.setDateFrom(dateFrom);
                nodeObj.setDateTo(dateTo);
                nodeObj.setEntrySum(nodeObj.getEntrySum() + nodeData.getEntryNum());
                nodeObj.setExitSum(nodeObj.getExitSum() + nodeData.getExitNum());

                List<NodeData> list = new ArrayList<NodeData>();
                list.add(nodeData);
                nodeObj.setList(list);

                linkedList.add(nodeObj);
            } else {
                NodeObj nodeObj = null;
                for (NodeObj _nodeObj : linkedList) {
                    boolean contain = isContain(nodeData, _nodeObj);
                    if (contain) {
                        nodeObj = _nodeObj;
                        break;
                    }
                }
                if (nodeObj != null) {
                    List<NodeData> list = nodeObj.getList();
                    list.add(nodeData);
                    nodeObj.setEntrySum(nodeObj.getEntrySum() + nodeData.getEntryNum());
                    nodeObj.setExitSum(nodeObj.getExitSum() + nodeData.getExitNum());
                } else {
                    nodeObj = new NodeObj();

                    Date requestDate = nodeData.getRequestDate();                 
                    requestDate = getNextSecond(requestDate,1);
                    nodeData.setRequestDate(requestDate);

                    String dateStr = sdf1.format(requestDate);
                    Date dateFrom = sdf2.parse(dateStr);
                    Date dateTo = getNextMinutes(dateFrom,timespace);

                    nodeObj.setDateFrom(dateFrom);
                    nodeObj.setDateTo(dateTo);
                    nodeObj.setEntrySum(nodeObj.getEntrySum() + nodeData.getEntryNum());
                    nodeObj.setExitSum(nodeObj.getExitSum() + nodeData.getExitNum());

                    List<NodeData> list = new ArrayList<NodeData>();
                    list.add(nodeData);
                    nodeObj.setList(list);

                    linkedList.add(nodeObj);

                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    public static boolean isContain(NodeData nodeData, NodeObj nodeObj) {
        boolean result = false;
        try {
            Date requestDate = nodeData.getRequestDate();
            requestDate = sdf2.parse(sdf2.format(requestDate));
            Date dateFrom = nodeObj.getDateFrom();
            dateFrom = sdf2.parse(sdf2.format(dateFrom));
            Date dateTo = nodeObj.getDateTo();
            dateTo = sdf2.parse(sdf2.format(dateTo));

            dateTo = getNextSecond(dateTo,-1);
            if (dateFrom.compareTo(requestDate) <= 0 && dateTo.compareTo(requestDate) >= 0) {
                result = true;
            }

            // System.out.println("isContain : requestDate=" + sdf2.format(requestDate) +
            // ", dateFrom="
            // + sdf2.format(dateFrom) + ", dateTo=" + sdf2.format(dateTo) + ", compareTo1="
            // + dateFrom.compareTo(requestDate) + ", compareTo2=" + dateTo.compareTo(requestDate) +
            // ", result="
            // + result);

        } catch (Exception ex) {
            ex.printStackTrace();
        }

        return result;
    }

    public static DataResult getFirst() throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
        DataResult dataResult = new DataResult();

        if (linkedList.size() > limit) {
            NodeObj first = linkedList.getFirst();
            dataResult.setDateFrom(first.getDateFrom());
            dataResult.setDateTo(first.getDateTo());
            dataResult.setEntrySum(first.getEntrySum());
            dataResult.setExitSum(first.getExitSum());
            Map<String, DataElement> dataElementMap = new LinkedHashMap<String, DataElement>();
            dataResult.setDataElementMap(dataElementMap);
            List<NodeData> list = first.getList();
            if (!CollectionUtils.isEmpty(list)) {
                for (NodeData nodeData : list) {
                    if (nodeData == null || nodeData.getCreativeId() == null) {
                        continue;
                    }
                    // 按创意分组
                    DataElement dataElement = dataElementMap.get(nodeData.getCreativeId());
                    if (dataElement == null) {
                        dataElement = new DataElement();
                    }
                    dataElement.setRequestCount(dataElement.getRequestCount() + 1);
                    //统计 step和cont
                    List<MyField> dataelementArray = CommonMethod.addStepToCount(dataElement,nodeData);
                    dataElement = CommonMethod.setDataElementValue(dataelementArray);
                   
                    dataElement.setTimeOutCount(dataElement.getTimeOutCount() + nodeData.getIsTimeOut());
                    dataElementMap.put(nodeData.getCreativeId(), dataElement);
                }
            }
            linkedList.remove(first);
        }

        // System.out.println(JSON.toJSONString(dataResult));

        return dataResult;

    }

    public static DataResult getNodeObj(NodeObj nodeObj) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
        DataResult dataResult = new DataResult();

        dataResult.setDateFrom(nodeObj.getDateFrom());
        dataResult.setDateTo(nodeObj.getDateTo());
        dataResult.setEntrySum(nodeObj.getEntrySum());
        dataResult.setExitSum(nodeObj.getExitSum());
        Map<String, DataElement> dataElementMap = new LinkedHashMap<String, DataElement>();
        dataResult.setDataElementMap(dataElementMap);
        List<NodeData> list = nodeObj.getList();
        if (!CollectionUtils.isEmpty(list)) {
            for (NodeData nodeData : list) {
                if (nodeData == null || nodeData.getCreativeId() == null) {
                    continue;
                }
                // 按创意分组
                DataElement dataElement = dataElementMap.get(nodeData.getCreativeId());
                if (dataElement == null) {
                    dataElement = new DataElement();
                }
                dataElement.setRequestCount(dataElement.getRequestCount() + 1);
                //统计 step和cont
                List<MyField> dataelementArray = CommonMethod.addStepToCount(dataElement,nodeData);
                dataElement = CommonMethod.setDataElementValue(dataelementArray);
                dataElement.setTimeOutCount(dataElement.getTimeOutCount() + nodeData.getIsTimeOut());
                dataElementMap.put(nodeData.getCreativeId(), dataElement);
            }
        }
        return dataResult;
    }

    public static void write(DataResult dataResult) {
        FileOutputStream writerStream = null;
        BufferedWriter writer = null;
        try {
            if (dataResult != null) {
                Date dateFrom = dataResult.getDateFrom();
                if (dateFrom != null) {
                    String dateFromStr = sdf3.format(dateFrom);
                    // 每天一个文件
                    String path = filePath + "tj." + dateFromStr + ".txt";
                    File file = new File(path);
                    if (!file.exists()) {
                        file.createNewFile();
                    }
                    writerStream = new FileOutputStream(file, true);
                    writer = new BufferedWriter(new OutputStreamWriter(writerStream, "UTF-8"));

                    StringBuffer sb = new StringBuffer();
                    sb.append("\n");
                    sb.append(sdf2.format(dataResult.getDateFrom()) + " --- " + sdf2.format(dataResult.getDateTo()));
                    sb.append("\n\n");
                    sb.append("entrySum=" + dataResult.getEntrySum() + " , exitSum=" + dataResult.getExitSum());
                    sb.append("\n\n");
                    Map<String, DataElement> dataElementMap = dataResult.getDataElementMap();
                    Set<String> keys = dataElementMap.keySet();
                    sb.append("*************************************");
                    sb.append("\n");
                    
                    DataElement element = new DataElement();
                    sb.append("creativeId | ");
                    List<MyField> elementArray = CommonMethod.getElementArrayList(element);
                    for (MyField field : elementArray) {
                        if(field.getName().length() < 12){
                            sb.append("  "); 
                        }
                        sb.append(field.getName() + " | "); 
                    }
                    sb.append("\n");
                    
                                       
                    for (String key : keys) {
                        DataElement dataElement = dataElementMap.get(key);
                        String str = String.format("% 10d", Integer.valueOf(key));
                        sb.append(str + " | ");
                        List<MyField> dataelementArray = CommonMethod.getElementArrayList(dataElement);
                        
                        for (MyField field : dataelementArray) {
                            String str2 = String.format("% 12d", Integer.valueOf(field.getValue()));
                            sb.append(str2 + " | ");
                        
                        }
                        sb.append("\n");
                    }
                    sb.append("\n");
                    sb.append("*************************************");
                    sb.append("\n");
                    System.out.println(sb.toString());
                    writer.write(sb.toString());
                    writer.flush();
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            try {
                if (writer != null) {
                    writer.close();
                }
                if (writerStream != null) {
                    writerStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static Date getNextMinutes(Date dateFrom,int mytimespace) throws ParseException{
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(dateFrom);
        calendar.add(Calendar.MINUTE, mytimespace);
        Date dateTo = calendar.getTime();
        return dateTo; 
    }
    
    public static Date getNextSecond(Date dateFrom,int mytimespace) throws ParseException{
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(dateFrom);
        calendar.add(Calendar.SECOND, mytimespace);
        Date dateTo = calendar.getTime();
        return dateTo; 
    }
    
    
    public static void main(String[] args) throws Exception {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        for (int i = 0; i < 262; i++) {
            NodeData nodeData = new NodeData();
            nodeData.setRequestDate(new Date());
            nodeData.setResponseDate(new Date());
            nodeData.setCreativeId(i + "");
            nodeData.setStep1(1);
            nodeData.setStep2(1);
            nodeData.setStep6(1);
            nodeData.setStep7(1);
            nodeData.setStep8(1);
            nodeData.setIsTimeOut(0);
            nodeData.setEntryNum(1);
            nodeData.setExitNum(1);
            handle(nodeData);
            Thread.sleep(1000);
        }
    }

}
